﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using FlaUI.Core.AutomationElements;
using FlaUI.Core.Conditions;
using FlaUI.Core.Definitions;
using FlaUI.Core.Exceptions;
using FlaUI.Core.Input;
using FlaUI.Core.Tools;
using FlaUI.UIA3;
using QQTools.Logging;


namespace QQTools.Utils
{
    public static class FlauiAuto
    {

        /// <summary>
        /// 模拟鼠标悬停到控件上。
        /// </summary>
        /// <param name="element">目标控件。</param>
        public static void HoverOverControl(AutomationElement element)
        {
            var boundingRect = element.Properties.BoundingRectangle.Value;

            if (boundingRect.IsEmpty)
            {
                Console.WriteLine("无法获取控件的边界信息！");
                return;
            }

            // 计算控件中心坐标
            int centerX = (int)(boundingRect.X + boundingRect.Width / 2);
            int centerY = (int)(boundingRect.Y + boundingRect.Height / 2);

            // 移动鼠标到控件中心
            Mouse.MoveTo(centerX, centerY);
            Console.WriteLine($"鼠标已移动到控件中心: ({centerX}, {centerY})");
        }

        // <summary>
        /// 获取控件的工具条提示值。
        /// </summary>
        /// <param name="element">目标控件。</param>
        /// <returns>工具条提示的值。如果未找到工具条提示，则返回 null。</returns>
        public static string GetTooltipValue(AutomationElement element)
        {
            try
            {
                // 检查控件是否支持 Tooltip 属性
                var tooltip = element.Properties.HelpText.Value;

                if (string.IsNullOrEmpty(tooltip))
                {
                    Console.WriteLine("该控件没有工具条提示！");
                    return null;
                }

                return tooltip;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取工具条提示失败: {ex.Message}");
                return null;
            }
        }

        public static void ClearAndSendKeys(AutomationElement editor, string text)
        {
            // 参数校验
            if (editor == null)
            {
                LogManager.Error("[ClearAndSendKeys] element 为空！");
                return;
            }

            if (string.IsNullOrEmpty(text))
            {
                // 如果 keys 为空或 null，则仅清空内容而不发送任何键
                LogManager.Error($"[ClearAndSendKeys] 输入内容为空");
                return;
            }

            try
            {
                // 确保元素可以被点击
                if (editor.IsEnabled)
                {
                    // 删除 text 中的特殊字符
                    long t = long.Parse(text);
                    if (t < 0)
                    {
                        return;
                    }
                    text = t.ToString();
                    editor.Click();
                    SendKeys.SendWait("^a"); // Ctrl+A选中所有文本
                    // SendKeys.SendWait("{DEL}"); // 删除选择的文本
                    SendKeys.SendWait(text);
                    return;
                }
                else
                {
                    LogManager.Error("[ClearAndSendKeys] element 不可点击！");
                    // 采用坐标点击方式
                    try
                    {
                        ClickControlCenter(editor);
                    }
                    catch (Exception ex)
                    {
                        LogManager.Error($"[ClearAndSendKeys] 坐标点击失败->原因：{ex.Message}");
                    }
                }
            }
            catch (Exception ex)
            {
                // 异常处理与日志记录
                LogManager.Error($"[ClearAndSendKeys] 点击失败->原因: {ex.Message}");
            }
        }


        public static void ClickControlCenter(AutomationElement element)
        {
            if (element == null)
            {
                LogManager.Error($"[ClickControlCenter] element为空! ");
                return;
            }

            // 获取目标窗口的中心坐标
            var center = GetControlCenter(element);
            if (center.HasValue)
            {
                Console.WriteLine($"控件中心坐标: ({center.Value.X}, {center.Value.Y})");
                // 点击控件中心
                Mouse.MoveTo(center.Value.X, center.Value.Y);
                Mouse.LeftClick();
            }
            else
            {
                LogManager.Error($"[ClickControlCenter] 无法获取控件中心坐标! ");
            }
        }


        /// <summary>
        /// 获取控件的中心坐标。
        /// </summary>
        /// <param name="element">目标控件的 AutomationElement。</param>
        /// <returns>控件的中心坐标 (X, Y)。如果无法获取边界信息，则返回 null。</returns>
        public static (int X, int Y)? GetControlCenter(AutomationElement element)
        {
            try
            {
                // 获取控件的边界矩形
                var boundingRect = element.Properties.BoundingRectangle.Value;

                if (boundingRect.IsEmpty)
                {
                    Console.WriteLine("无法获取控件的边界信息！");
                    return null;
                }

                // 计算中心坐标
                int centerX = boundingRect.X + boundingRect.Width / 2;
                int centerY = boundingRect.Y + boundingRect.Height / 2;

                return (centerX, centerY);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取控件中心坐标失败: {ex.Message}");
                return null;
            }
        }



        /// <summary>
        /// 根据 AutomationElement 关闭窗口。
        /// </summary>
        /// <param name="control"></param>
        public static void CloseWindow(AutomationElement control)
        {
            try
            {
                if (control == null)
                {
                    LogManager.Warn("[关闭窗口] AutomationElement 无效");
                    return;
                }
                string title = "窗口标题为空";
                // 检查control是否支持Name
                if (control.Properties.Name.IsSupported)
                {
                    title = control.Name;
                }

                IntPtr hwnd = control.Properties.NativeWindowHandle.Value;
                if (hwnd == IntPtr.Zero)
                {
                    LogManager.Warn("[关闭窗口] 窗口句柄无效");
                    return;
                }
                // 窗口置顶
               // control.SetForeground();

                // 检查窗口是否可见
                //if (!control.IsOffscreen)
                //{
                //    LogManager.Warn($"[关闭窗口] 窗口不可见, 标题: {title}");
                //    return;
                //}
                // 判断 control 是不是 窗口
                if (control.ControlType != ControlType.Window)
                {
                    LogManager.Warn($"[关闭窗口] 不是窗口类型, 无法关闭 标题: {title}");
                    return;
                }
                // control?.AsWindow()?.Close(); // 关闭窗口
                // 发送 WM_CLOSE 消息关闭窗口
                Win32Api.CloseWindow(hwnd);
                LogManager.Info($"[关闭窗口] 成功关闭窗口, 标题:{title} hwnd: {hwnd}");
            }
            catch (Exception ex)
            {
                LogManager.Error($"[关闭窗口] 发生异常1: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 在指定的父元素中查找符合给定名称的控件。
        /// </summary>
        /// <param name="parent">要搜索的父元素。</param>
        /// <param name="controlType">控件的类型。</param>
        /// <param name="controlName">控件的名称。</param>
        /// <param name="nameMatchFlags">名称匹配选项，默认为None。</param>
        /// <param name="timeoutSeconds">查找控件的超时时间，默认为5秒。</param>
        /// <param name="pollingIntervalMs">轮询间隔时间，默认为500毫秒。</param>
        /// <returns>找到的控件元素，如果未找到则返回null。</returns>
        public static AutomationElement FindControl(
            this AutomationElement parent,
            ControlType controlType,
            string controlName,
            PropertyConditionFlags nameMatchFlags = PropertyConditionFlags.None,
            Double timeoutSeconds = 3,
            Double pollingIntervalMs = 500)
        {
            // 参数校验
            if (parent == null)
            {
                LogManager.Error("parent 参数为 null", new ArgumentNullException(nameof(parent)));
                throw new ArgumentNullException(nameof(parent));
            }
            if (string.IsNullOrEmpty(controlName))
            {
                LogManager.Error("controlName 参数为空", new ArgumentException("控件名称不能为空", nameof(controlName)));
                throw new ArgumentException("控件名称不能为空", nameof(controlName));
            }
            if (timeoutSeconds < 0)
            {
                LogManager.Error("timeoutSeconds 参数为负数", new ArgumentOutOfRangeException(nameof(timeoutSeconds), "超时时间不能为负数"));
                throw new ArgumentOutOfRangeException(nameof(timeoutSeconds), "超时时间不能为负数");
            }
            if (pollingIntervalMs <= 0)
            {
                LogManager.Error("pollingIntervalMs 参数小于等于0", new ArgumentOutOfRangeException(nameof(pollingIntervalMs), "轮询间隔必须大于0"));
                throw new ArgumentOutOfRangeException(nameof(pollingIntervalMs), "轮询间隔必须大于0");
            }

            // 构建条件
            var cf = new ConditionFactory(new UIA3PropertyLibrary());
            var condition = cf
                .ByControlType(controlType)
                .And(cf.ByName(controlName, nameMatchFlags));
            LogManager.Info($"开始查找控件: {controlName}");

            // 查找元素，最多重试3次，每次间隔1秒
            AutomationElement result = Retry.Find(
                () =>
                {
                    try
                    {
                        var control = parent.FindFirstDescendant(condition);
                        if (control != null)
                        {
                            LogManager.Info($"找到控件: {controlName}");
                        }
                        else
                        {
                            LogManager.Warn($"未找到控件: {controlName}");
                        }
                        return control;
                    }
                    catch (Exception ex) when (IsExpectedException(ex))
                    {
                        LogManager.Warn($"查找控件时预期异常: {ex.Message}");
                        return null;
                    }
                    catch (Exception ex)
                    {
                        LogManager.Error($"查找控件时发生异常: {controlName}", ex);
                        return null;
                    }
                },
                new RetrySettings
                {
                    Timeout = TimeSpan.FromSeconds(timeoutSeconds),
                    Interval = TimeSpan.FromMilliseconds(pollingIntervalMs)
                }
             );

            return result;
        }

        /// <summary>
        /// 判断是否为预期内的可忽略异常
        /// </summary>
        private static bool IsExpectedException(Exception ex)
        {
            return ex is ElementNotAvailableException ||
                   ex is InvalidOperationException; // 父元素状态无效
        }

        /// <summary>
        /// 根据XPath在指定的父元素中查找元素，并等待直到找到元素或超时。
        /// 默认超时时间为5秒，查询间隔为0.5秒。
        /// </summary>
        /// <param name="parent">父元素</param>
        /// <param name="xPath">xPath</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="pollingInterval">查找间隔</param>
        /// <returns>找到的元素，如果未找到则返回null</returns>
        public static async Task<AutomationElement> FindElementByXPathAsync(AutomationElement parent, string xPath, TimeSpan? timeout = null, TimeSpan? pollingInterval = null)
        {
            // 参数验证
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent), "父元素不能为空");
            }
            if (string.IsNullOrWhiteSpace(xPath))
            {
                throw new ArgumentException("XPath 不能为空或空白", nameof(xPath));
            }


            // 设置默认超时时间为5秒
            if (timeout == null)
            {
                timeout = TimeSpan.FromSeconds(5);
            }

            // 设置默认查询间隔为0.5秒
            if (pollingInterval == null)
            {
                pollingInterval = TimeSpan.FromMilliseconds(500);
            }

            // 使用 Stopwatch 计算超时时间
            var stopwatch = Stopwatch.StartNew();
            AutomationElement element = null;

            while (stopwatch.Elapsed < timeout)
            {
                try
                {
                    element = parent.FindFirstByXPath(xPath);
                    if (element != null)
                    {
                        return element;
                    }
                }
                catch (Exception ex)
                {
                    // 可以根据需要记录日志或抛出自定义异常
                    Console.WriteLine($"查找元素时发生异常: {ex.Message}");
                }
                await Task.Delay(pollingInterval.Value);
            }
            return null;
        }
    }
}
